using Sage.Http.Models;
using Sage.Http.Utils;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;

namespace Sage.Http.Core.Handlers
{
    /// <summary>
    /// 请求内容处理器，负责处理所有与请求内容相关的逻辑
    /// </summary>
    internal class RequestContentHandler
    {
        private string? _body;
        private BodyType _bodyType = BodyType.Json;
        private HttpContent? _content;
        private readonly Dictionary<string, string> _formData = [];
        private readonly List<FileParameter> _files = [];

        /// <summary>
        /// 获取请求体内容
        /// </summary>
        public string? Body => _body;

        /// <summary>
        /// 获取请求体类型
        /// </summary>
        public BodyType BodyType => _bodyType;

        /// <summary>
        /// 获取HttpContent
        /// </summary>
        public HttpContent? Content => _content;

        /// <summary>
        /// 获取表单数据
        /// </summary>
        public IReadOnlyDictionary<string, string> FormData => _formData;

        /// <summary>
        /// 获取文件列表
        /// </summary>
        public IReadOnlyList<FileParameter> Files => _files;

        /// <summary>
        /// 设置请求体内容
        /// </summary>
        /// <param name="body">请求体内容</param>
        /// <param name="bodyType">内容类型</param>
        public void SetBody(string body, BodyType bodyType)
        {
            _body = body;
            _bodyType = bodyType;
            _content = null; // 清除直接设置的HttpContent，避免冲突
        }

        /// <summary>
        /// 设置请求体内容（字典版本）
        /// </summary>
        /// <param name="data">要转换的字典数据</param>
        /// <param name="bodyType">内容类型</param>
        public void SetBody(IDictionary<string, object> data, BodyType bodyType)
        {
            ArgumentNullException.ThrowIfNull(data);
            string convertedBody = DictionaryConverter.ConvertToString(data, bodyType);
            SetBody(convertedBody, bodyType);
        }

        /// <summary>
        /// 设置JSON内容（AOT兼容版本）
        /// </summary>
        /// <typeparam name="T">内容类型</typeparam>
        /// <param name="value">要序列化为JSON的对象</param>
        /// <param name="jsonTypeInfo">JSON类型信息，用于AOT环境</param>
        public void SetJsonContent<T>(T value, JsonTypeInfo<T> jsonTypeInfo)
        {
            ArgumentNullException.ThrowIfNull(value);
            ArgumentNullException.ThrowIfNull(jsonTypeInfo);

            string json = JsonSerializer.Serialize(value, jsonTypeInfo);
            SetBody(json, BodyType.Json);
        }

        /// <summary>
        /// 设置JSON内容（非AOT兼容版本）
        /// </summary>
        /// <typeparam name="T">内容类型</typeparam>
        /// <param name="value">要序列化为JSON的对象</param>
        [RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        [RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        public void SetJsonContent<T>(T value)
        {
            ArgumentNullException.ThrowIfNull(value);
            string json = JsonSerializer.Serialize(value);
            SetBody(json, BodyType.Json);
        }

        /// <summary>
        /// 设置JSON内容（带选项）
        /// </summary>
        /// <typeparam name="T">内容类型</typeparam>
        /// <param name="value">要序列化为JSON的对象</param>
        /// <param name="options">JSON序列化选项</param>
        [RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        [RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
        public void SetJsonContent<T>(T value, JsonSerializerOptions options)
        {
            ArgumentNullException.ThrowIfNull(value);
            ArgumentNullException.ThrowIfNull(options);

            string json = JsonSerializer.Serialize(value, options);
            SetBody(json, BodyType.Json);
        }

        /// <summary>
        /// 设置XML内容
        /// </summary>
        /// <param name="xmlContent">XML内容字符串</param>
        public void SetXmlContent(string xmlContent)
        {
            SetBody(xmlContent, BodyType.Xml);
        }

        /// <summary>
        /// 设置纯文本内容
        /// </summary>
        /// <param name="textContent">文本内容</param>
        public void SetTextContent(string textContent)
        {
            SetBody(textContent, BodyType.Text);
        }

        /// <summary>
        /// 设置HttpContent
        /// </summary>
        /// <param name="content">HttpContent实例</param>
        public void SetContent(HttpContent content)
        {
            ArgumentNullException.ThrowIfNull(content);
            _content = content;
            _body = null; // 清除字符串内容，避免冲突
        }

        /// <summary>
        /// 添加表单字段
        /// </summary>
        /// <param name="name">字段名</param>
        /// <param name="value">字段值</param>
        public void AddFormField(string name, string value)
        {
            ArgumentNullException.ThrowIfNull(name);
            ArgumentNullException.ThrowIfNull(value);

            _formData[name] = value;
            _bodyType = BodyType.MultipartFormData;
            _content = null; // 清除直接设置的HttpContent，避免冲突
        }

        /// <summary>
        /// 添加多个表单字段
        /// </summary>
        /// <param name="formData">表单数据字典</param>
        public void AddFormFields(IDictionary<string, string> formData)
        {
            ArgumentNullException.ThrowIfNull(formData);

            foreach (var field in formData)
            {
                AddFormField(field.Key, field.Value);
            }
        }

        /// <summary>
        /// 添加文件参数
        /// </summary>
        /// <param name="file">文件参数</param>
        public void AddFile(FileParameter file)
        {
            ArgumentNullException.ThrowIfNull(file);

            _files.Add(file);
            _bodyType = BodyType.MultipartFormData;
            _content = null; // 清除直接设置的HttpContent，避免冲突
        }

        /// <summary>
        /// 添加多个文件参数
        /// </summary>
        /// <param name="files">文件参数列表</param>
        public void AddFiles(IEnumerable<FileParameter> files)
        {
            ArgumentNullException.ThrowIfNull(files);

            foreach (var file in files)
            {
                AddFile(file);
            }
        }

        /// <summary>
        /// 清除所有内容
        /// </summary>
        public void Clear()
        {
            _body = null;
            _bodyType = BodyType.Json;
            _content = null;
            _formData.Clear();
            _files.Clear();
        }

        /// <summary>
        /// 将内容应用到HttpRequestMessage
        /// </summary>
        /// <param name="request">HTTP请求消息</param>
        /// <param name="progress">进度报告接口（可选）</param>
        /// <param name="cancellationToken">取消令牌（可选）</param>
        public void ApplyContent(HttpRequestMessage request, IProgress<float>? progress = null, CancellationToken cancellationToken = default)
        {
            ArgumentNullException.ThrowIfNull(request);

            // 优先使用直接设置的HttpContent
            if (_content != null)
            {
                request.Content = progress != null
                    ? new Content.ProgressableStreamContent(_content, progress, cancellationToken: cancellationToken)
                    : _content;
                return;
            }

            // 其次处理表单数据
            if (_bodyType == BodyType.MultipartFormData)
            {
                var multipartContent = HttpRequestManager.CreateMultipartContent(_formData, _files);

                request.Content = progress != null
                    ? new Content.ProgressableStreamContent(multipartContent, progress, cancellationToken: cancellationToken)
                    : multipartContent;
            }
            // 最后处理字符串内容
            else if (!string.IsNullOrEmpty(_body))
            {
                var stringContent = HttpRequestManager.CreateStringContent(_body, _bodyType);

                request.Content = progress != null
                    ? new Content.ProgressableStreamContent(stringContent, progress, cancellationToken: cancellationToken)
                    : stringContent;
            }
        }
    }
}